#include "object.h"


// perform basic physics on the object
void CObject::OnAnimate(scalar_t deltaTime) 
{
	position += velocity * deltaTime;
	velocity += acceleration * deltaTime;
}

// perform collision and other preparations for this object
void CObject::OnPrepare() 
{
	ProcessCollisions(FindRoot());		// perform collisions starting with root world object
}

CObject::CObject()
{
	isDead = false;
}

CObject::~CObject() {}

void CObject::Draw(CCamera *camera) // draw object
{
	// push modelview matrix on stack
	glPushMatrix();
		OnDraw(camera);		// draw this object
		if (HasChild())		// draw children
			((CObject*)childNode)->Draw(camera);
	glPopMatrix();

	// draw siblings
	if (HasParent() && !IsLastChild())
		((CObject*)nextNode)->Draw(camera);
}

void CObject::Animate(scalar_t deltaTime) // animate object
{
	// animate this object
	OnAnimate(deltaTime);

	// animate children
	if (HasChild())
		((CObject*)childNode)->Animate(deltaTime);

	// animate siblings
	if (HasParent() && !IsLastChild())
		((CObject*)nextNode)->Animate(deltaTime);

	if (isDead)
		delete this;
}

void CObject::ProcessCollisions(CObject *obj) // perform collision detection
{
	// if this object's bounding sphere collides with obj's sphere
	// and obj is not this object
	if (((obj->position - position).Length() <= (obj->size + size)) &&
		(obj != ((CObject*)this)))
	{
		// perform this object's collision with obj
		OnCollision(obj);

		// test child collisions with obj
		if (HasChild())
			((CObject*)childNode)->ProcessCollisions(obj);

		// test sibling collisions with obj
		if (HasParent() && !IsLastChild())
			((CObject*)nextNode)->ProcessCollisions(obj);
	}

	// if obj has children, check collisions with these children
	if (obj->HasChild())
		ProcessCollisions((CObject*)(obj->childNode));

	// if obj has siblings, check collisions with these siblings
	if (obj->HasParent() && !obj->IsLastChild())
		ProcessCollisions((CObject*)(obj->nextNode));
}

void CObject::Prepare() // prepare object
{
	OnPrepare();							// prepare this object

	if (HasChild())							// prepare children
		((CObject*)childNode)->Prepare();

	if (HasParent() && !IsLastChild())		// prepare siblings
		((CObject*)nextNode)->Prepare();
}

CObject* CObject::FindRoot() // find root object of cyclic linked list tree
{
	// if this object has a parent node, return the root of the parent node
	if (parentNode)
		return ((CObject*)parentNode)->FindRoot();

	return this;
}

double CObject::DistanceToObject(CObject* obj)
{
	CVector thisPos = this->position;
	CVector objPos = obj->position;
	float dx = thisPos.GetX() - objPos.GetX();
	float dz = thisPos.z - objPos.z;
	float dist = sqrt(dx*dx + dz*dz);
	return dist;
}
